
package com.phychips.utility;

import android.annotation.SuppressLint;


public class EpcConverter
{
    public final static int HEX_STRING = 0;
    public final static int ASCII = 1;
    public final static int SGTIN96 = 2;    
    public final static int EAN13 = 3;    
    
    private final static int ID_SGTIN96 = 0x30;
    private final static int[] gWeighting = { 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3 };
    private final static int[] gCompanyPrefixBitLen = {40, 37, 34, 30, 27, 24, 20};
    public static String toTypeString(int type)
    {
	switch(type)
	{
	case HEX_STRING:
	    return "HEX";
	case ASCII:
	    return "ASCII";
	case SGTIN96:
	    return "SGTIN96";
	case EAN13:
	    return "EAN13";
	}
	
	return null;	
    }
    
    public static String toAscii(int[] data)
    {
	StringBuilder sb = new StringBuilder(data.length);
	for (int i = getEpcStartDigit(data); i < data.length; i++)
	{	    
	    if (data[i] > 0 && data[i] < 127)
		sb.append(Character.toString ((char) (data[i] & 0xff)));
	    else
		sb.append(" ");
	}
	return sb.toString();
    }
    
    @SuppressLint("DefaultLocale")
    public static String toHexString(int[] data)
    {
	StringBuffer sb = new StringBuffer();
		   
	for (int i = 0; i < data.length; i++)
	{
	    String hex = Integer.toHexString(data[i]&0xff).toUpperCase();
	    if (hex.length() < 2) 
	    {
	        sb.append('0'); // pad with leading zero if needed
	    }	    
	    sb.append(hex);
	    //sb.append(String.format("%02X", data[i]&0xff));
	}
	return sb.toString();
    }
    
    private static String toBinString(int[] data)
    {
	if(data.length < 14)
	    return "";
	
	int startDigit = getEpcStartDigit(data);
	
	if(data.length < 12 + startDigit)
	    return "";
	
	if(data [startDigit] != ID_SGTIN96) // PC (2 bytes) + EPC
	    return "";
	
	StringBuffer sb = new StringBuffer();
	
	for (int i = startDigit + 1; i < data.length; i++)
	{	    
	    
	    String bin = Integer.toBinaryString((data[i]&0xff));
	    if(bin.length() < 8)
	    {
		for(int j = 0; j < 8 - bin.length(); j++)
		    sb.append('0');
	    }
	    sb.append(bin);
	    //sb.append(String.format("%08d", Integer.parseInt(Integer.toBinaryString((data[i]&0xff)))));
	}   
	
	//System.out.println("binString = " + sb.toString());
	
	return sb.toString();
    }
    
    private static int getPartition(String bin)
    {	
	//System.out.println("Partition = " + bin.substring(3, 6) + "[" + Integer.parseInt(bin.substring(3, 6),2) + "]");	
	 return  Integer.parseInt(bin.substring(3, 6),2);
    }
    
    private static String getCompanyPrefix(String bin) 
    {
	int nPartition = getPartition(bin);
	int nCompanyPrefixLen = getCompanyPrefixBitLen(nPartition);
	String binCompanyPrefix = bin.substring(6, 6 + nCompanyPrefixLen);
	long nCompanyPrefix = Long.parseLong(binCompanyPrefix, 2);
	int digitCompanyPrefixLen = 12 - nPartition;
	
	return padLeft(Long.toString(nCompanyPrefix), digitCompanyPrefixLen,
		"0");
    }
    
    private static int getCompanyPrefixBitLen(int partition)
    {
	if(partition < 0 || partition > 6)
	    return 0;
	
	return gCompanyPrefixBitLen[partition];
    }
    
    private static String getItemReference(String bin)
    {
	int nPartition = getPartition(bin);
	int nCompanyPrefixLen = getCompanyPrefixBitLen(nPartition);			
	int nItemReferenceLen = 44 - nCompanyPrefixLen;	
	String binItemReference = bin.substring(6 + nCompanyPrefixLen, 6
		+ nCompanyPrefixLen + nItemReferenceLen);
	long nItemReference = Long.parseLong(binItemReference, 2);
	int digitItemReferenceLen = 1 + nPartition; 
	
	return padLeft(Long.toString(nItemReference), digitItemReferenceLen,
		"0");
    }
    
    private static String getSerial(String bin)
    {
	int nPartition = getPartition(bin);
	int nCompanyPrefixLen = getCompanyPrefixBitLen(nPartition);			
	int nItemReferenceLen = 44 - nCompanyPrefixLen;	
	String binSerial 
		= bin.substring(6 + nCompanyPrefixLen + nItemReferenceLen, 6
		+ nCompanyPrefixLen + nItemReferenceLen + 38);
	Long nSerial = Long.parseLong(binSerial, 2);	
	
	return Long.toString(nSerial);
    }
    
    private static String getFilter(String bin)
    {
	return Integer.toString(Integer.parseInt(bin.substring(0, 3),2));
    }
    
    public static String toSGTIN96(int[] data)
    {		
	String bin = toBinString(data);
	    
	if (bin.length() == 0)
	    return "NON-SGTIN96";
	else 
	    return getFilter(bin)
		+ "."
		+ getCompanyPrefix(bin)
		+ "."
		+ getItemReference(bin) 
		+ "." 
		+ getSerial(bin);	
    }
    
    public static String toEAN13(int[] data)
    {		
	String bin = toBinString(data);
	    
	if (bin.length() == 0)
	    return "NON-SGTIN96";
	else 
	{
	    String message = getCompanyPrefix(bin) + getItemReference(bin).substring(1);
	    
	    return appendParity(message);
	}	    
    }
    
    public static String toString(int type, int[] data)
    {
	if (type == ASCII)
	{
	    return toAscii(data);	    
	}
	else if(type == SGTIN96)
	{
	    return toSGTIN96(data);
	}
	else if(type == EAN13)
	{
	    return toEAN13(data);
	}
	else
	{
	    return toHexString(data);
	}
    }
    
    private static int getEpcStartDigit(int[] data)
    {
	int digit = 2; // PC
	
	if((data[0] & 0x02) == 0x02)
	{   
	    if((data[2] & 0x08) == 0x08)
	    {
		digit = 6; // PC + XPC_W1 + XPC_W2
	    }
	    else
	    {
		digit = 4; // PC + XPC_W1
	    }
	}	
	
	return digit;
    }
    
    // 	need to optimize
    private static String padLeft(String s, int n, String pad) 
    {
//	System.out.println("s = " + s);
//	System.out.println("n = " + n);
//	System.out.println("padLeft = " + String.format("%1$" + n + "s", s).replace(" ", pad));
	StringBuilder sb = new StringBuilder();
	if(s.length() < n)
	{
	    for(int i = 0; i < n - s.length(); i++)
	    {
		sb.append(pad);
	    }
	    
	}
	sb.append(s);
//	System.out.println("sb = " + sb.toString());
	return sb.toString();
	//return String.format("%1$" + n + "s", s).replace(" ", pad);  
    }
    
    private static String appendParity(String message)  
    {  	
        int sum = 0;  
        int parity = 0;  

        for(int i = 0; i < 12; i++)  
        {  
            sum += Integer.parseInt(message.substring(i, i+1)) * gWeighting[i];  
        }  

        parity = 10 - (sum % 10);  
        if (parity == 10)  
        {  
            parity = 0;  
        }
        
        return message + Integer.toString(parity);
    }  
}
